package appcus

import (
	"counter-help/admin/server/global"
	"counter-help/admin/server/model/app"
	appReq "counter-help/admin/server/model/app/request"
	appRes "counter-help/admin/server/model/app/response"
	"counter-help/admin/server/model/common/response"
	customerReq "counter-help/admin/server/model/customer/request"
	"counter-help/admin/server/model/system"
	"counter-help/admin/server/utils"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
)

type AppUserApi struct {
}

const (
	// 假设这是小程序appId和appSecret
	APP_ID     = "wx397aa4c18c836e69"
	APP_SECRET = "617081a01ebe46f6d8c255f0adae0f8b"
)

func (a *AppUserApi) Login(c *gin.Context) {
	// 获取小程序 Code
	var userReq appReq.WechatLoginRequest
	err := c.ShouldBindJSON(&userReq)
	if err != nil {
		global.GVA_LOG.Error("ShouldBindJSON Error:: " + err.Error())
		response.FailWithMessage("获取参数失败", c)
		return
	}

	// 获取 OpenId 和 Session Key
	openid, unionid, sessionKey, err := getOpenidAndSessionKey(userReq.Code)
	if err != nil {
		global.GVA_LOG.Error("Get OpenId and Session Key Error:: " + err.Error())
		response.FailWithMessage(err.Error(), c)
		return
	}

	// 获取手机号
	phoneData, err := decryptPhoneData(userReq.EncryptedData, userReq.Iv, sessionKey)
	if err != nil {
		global.GVA_LOG.Error("Decode PhoneData Error :: " + err.Error())
		response.FailWithMessage(err.Error(), c)
		return
	}

	// 获取 purePhoneNumber
	if purePhoneNumber, ok := phoneData["purePhoneNumber"].(string); ok {
		global.GVA_LOG.Info("手机号获取成功 Phone Number: " + purePhoneNumber)
	} else {

		global.GVA_LOG.Error("获取手机号失败 , 请检查解码参数 phoneData")
		fmt.Println("手机解码数据::", phoneData)
		response.FailWithMessage("获取手机号失败！", c)
		return
	}

	userInfo := app.AppUser{
		Openid:   openid,
		Unionid:  unionid,
		Phone:    phoneData["purePhoneNumber"].(string),
		NickName: userReq.NickName,
	}
	fmt.Println(userInfo)
	// 用户存在
	appUser, err := appUserService.Login(&userInfo)
	if err != nil {
		global.GVA_LOG.Error("用户登陆失败 Error:: " + err.Error())
		response.FailWithMessage(err.Error(), c)
		return
	}
	// 下发token
	a.tokenNext(c, appUser)
	return
}

// token 下发
func (a *AppUserApi) tokenNext(c *gin.Context, appUser *app.AppUser) {
	token, claims, err := utils.AppLoginToken(appUser)
	if err != nil {
		global.GVA_LOG.Error("获取token失败!", zap.Error(err))
		response.FailWithMessage("获取token失败", c)
		return
	}
	if !global.GVA_CONFIG.System.UseMultipoint {
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(appRes.AppLoginResponse{
			User:      *appUser,
			Token:     token,
			ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
		}, "登录成功", c)
		return
	}

	if jwtStr, err := jwtService.GetRedisJWT(appUser.Openid); err == redis.Nil {
		if err := jwtService.SetRedisJWT(token, appUser.Openid); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(appRes.AppLoginResponse{
			User:      *appUser,
			Token:     token,
			ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
		}, "登录成功", c)
	} else if err != nil {
		global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		var blackJWT system.JwtBlacklist
		blackJWT.Jwt = jwtStr
		if err := jwtService.JsonInBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		if err := jwtService.SetRedisJWT(token, appUser.GetOpenid()); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(appRes.AppLoginResponse{
			User:      *appUser,
			Token:     token,
			ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
		}, "登录成功", c)
	}
}

// 获取 Openid 和 sessionKey
func getOpenidAndSessionKey(code string) (openid, unionid, sessionKey string, err error) {
	// 请求微信接口，获取 Openid 和 SessionKey
	resp, err := http.Get(fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
		APP_ID, APP_SECRET, url.QueryEscape(code)))
	if err != nil {
		return "", "", "", fmt.Errorf("请求微信 API 错误: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", "", "", fmt.Errorf("读取微信响应失败: %v", err)
	}

	// 解析 JSON 响应
	var wechatResp appRes.WechatLoginResponse
	err = json.Unmarshal(body, &wechatResp)
	if err != nil {
		return "", "", "", fmt.Errorf("解析微信响应失败: %v", err)
	}

	// 检查微信返回的错误码
	if wechatResp.Errcode != 0 {
		return "", "", "", fmt.Errorf("微信接口错误: %s", wechatResp.Errmsg)
	}

	return wechatResp.Openid, wechatResp.Unionid, wechatResp.SessionKey, nil
}

func decryptPhoneData(encryptedData, iv, sessionKey string) (map[string]interface{}, error) {
	// Base64 解码 sessionKey、encryptedData 和 iv
	key, err := base64.StdEncoding.DecodeString(sessionKey)
	if err != nil {
		return nil, fmt.Errorf("sessionKey base64 解码失败: %v", err)
	}

	data, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		return nil, fmt.Errorf("encryptedData base64 解码失败: %v", err)
	}

	ivDecoded, err := base64.StdEncoding.DecodeString(iv)
	if err != nil {
		return nil, fmt.Errorf("iv base64 解码失败: %v", err)
	}

	// 初始化 AES 解密
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, fmt.Errorf("创建 AES 密钥失败: %v", err)
	}

	blockMode := cipher.NewCBCDecrypter(block, ivDecoded)
	decrypted := make([]byte, len(data))
	blockMode.CryptBlocks(decrypted, data)

	// 去除 PKCS#7 填充
	decrypted, err = pkcs7Unpadding(decrypted)
	if err != nil {
		return nil, err
	}
	// 解码 JSON 数据
	var result map[string]interface{}
	err = json.Unmarshal(decrypted, &result)
	if err != nil {
		fmt.Println("解码解密数据失败", err, encryptedData, iv, sessionKey, decrypted)
		return nil, fmt.Errorf("c: %v", err)
	}
	return result, nil
}

func pkcs7Unpadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("数据不符合 PKCS7 填充规范")
	}
	unpadding := int(data[length-1])
	return data[:(length - unpadding)], nil
}

// UpdateUserInfo 更新用户个人信息
// @Tags CusUser
// @Summary 更新用户个人信息
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /cusUser/updateInfo [put]

func (b *AppUserApi) UpdateUserInfo(c *gin.Context) {
	// 绑定请求中的 JSON 数据到结构体
	var req customerReq.UpdateUserInfoRequest
	if c.Request.FormValue("birth") != "" {
		intTime, err := strconv.ParseInt(c.Request.FormValue("birth"), 10, 64)
		if err != nil {
			response.FailWithMessage("解析生日字段错误", c)
			return
		}
		req.Birth = &intTime
	}
	if c.Request.FormValue("sex") != "" {
		req.Sex = c.Request.FormValue("sex")
	}
	if c.Request.FormValue("unit") != "" {
		req.Unit = c.Request.FormValue("unit")
	}
	if c.Request.FormValue("address") != "" {
		req.Address = c.Request.FormValue("address")
	}
	if c.Request.FormValue("nickname") != "" {
		req.Nickname = c.Request.FormValue("nickname")
	}
	if c.Request.FormValue("research") != "" {
		req.Research = c.Request.FormValue("research")
	}
	fmt.Printf("UpdateUserInfoRequest: %+v", req)

	var avatarPath string
	// 检查是否上传了头像文件
	if file, header, err := c.Request.FormFile("avatar"); err == nil {
		defer file.Close() // 确保文件在函数结束后被关闭

		if file != nil && header != nil {
			userID := utils.GetUserID(c)
			avatarDir := fmt.Sprintf("uploads/avatars/%d", userID)
			avatarPath = fmt.Sprintf("%s/avatar_%d%s", avatarDir, time.Now().Unix(), filepath.Ext(header.Filename))

			// 检查并创建目录
			if err := os.MkdirAll(avatarDir, os.ModePerm); err != nil {
				global.GVA_LOG.Error("创建存储目录失败!", zap.Error(err))
				response.FailWithMessage("创建存储目录失败", c)
				return
			}

			// 清空目录中的旧文件
			files, err := os.ReadDir(avatarDir)
			if err != nil {
				global.GVA_LOG.Error("读取存储目录失败!", zap.Error(err))
				response.FailWithMessage("读取存储目录失败", c)
				return
			}
			for _, file := range files {
				if err := os.Remove(fmt.Sprintf("%s/%s", avatarDir, file.Name())); err != nil {
					global.GVA_LOG.Error("删除旧文件失败", zap.Error(err))
					response.FailWithMessage("删除旧文件失败", c)
					return
				}
			}

			// 保存新头像文件
			out, err := os.Create(avatarPath)
			if err != nil {
				global.GVA_LOG.Error("头像文件保存失败!", zap.Error(err))
				response.FailWithMessage("头像文件保存失败", c)
				return
			}
			defer out.Close()

			// 将文件内容从 file 拷贝到目标文件
			if _, err := io.Copy(out, file); err != nil {
				global.GVA_LOG.Error("文件写入失败", zap.Error(err))
				response.FailWithMessage("文件写入失败", c)
				return
			}
		}
	}

	userID := utils.GetUserID(c)
	// 调用服务层方法进行更新
	if err := appUserService.UpdateUserInfo(int(userID), req, avatarPath); err != nil {
		global.GVA_LOG.Error("更新用户信息失败!", zap.Error(err))
		response.FailWithMessage("更新用户信息失败", c)
		return
	}

	response.OkWithMessage("用户信息更新成功", c)
}

// GetUserInfo 获取用户个人信息
// @Tags CusUser
// @Summary 获取用户个人信息
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=customerRes.UserInfoResponse,msg=string} "获取成功"
// @Router /cusUser/getInfo [get]
func (b *AppUserApi) GetUserInfo(c *gin.Context) {

	userID := utils.GetUserID(c)

	// 获取用户信息
	user, err := appUserService.GetUserInfo(userID)
	if err != nil {
		global.GVA_LOG.Error("获取用户信息失败!", zap.Error(err))
		response.FailWithMessage("获取用户信息失败", c)
		return
	}

	response.OkWithDetailed(user, "获取成功", c)
}
